﻿using Microsoft.Win32;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Drawing.Imaging;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace FileExplorer
{
    /// <summary>
    /// 文件信息工具类
    /// </summary>
    public class FileInfoTool
    {
        /// <summary>
        /// 转化long为文件大小字符串形式
        /// </summary>
        public static string ToSizeStr(long FileLength)
        {
            string[] UNIT = { "B", "KB", "MB", "GB", "TB" };
            int i = 0;

            double len = FileLength;
            while (len > 1024)
            {
                len = Math.Round((len / 1024.0), 2);
                i++;
                if (i == UNIT.Length - 1) break;
            }

            return len + " " + UNIT[i];
        }

        /// <summary>
        /// 获取文件扩展名对应的描述信息
        /// </summary>
        public static string GetDescription(string extension)
        {
            string description = "";

            //从注册表中读取扩展名相应的子键
            RegistryKey extsubkey = Registry.ClassesRoot.OpenSubKey(extension);
            if (extsubkey == null)  //没有找到，那就是这种类型
            {
                description = extension.ToUpper().Substring(1) + "文件";
                return description;
            }

            //取出扩展名对应的文件类型名称  
            string extdefaultvalue = extsubkey.GetValue(null) as string;
            if (extdefaultvalue == null) return description;

            //扩展名类型是可执行文件
            if (extdefaultvalue.Equals("exefile", StringComparison.InvariantCultureIgnoreCase))
            {
                //从注册表中读取文件类型名称的相应子键  
                RegistryKey exefilesubkey = Registry.ClassesRoot.OpenSubKey(extdefaultvalue);
                if (exefilesubkey != null)  //如果不为空
                {
                    string exefiledescription = exefilesubkey.GetValue(null) as string;   //得到exefile描述字符串  
                    if (exefiledescription != null)
                    {
                        description = exefiledescription;
                    }
                }
                return description;
            }

            //从注册表中读取文件类型名称的相应子键  
            RegistryKey typesubkey = Registry.ClassesRoot.OpenSubKey(extdefaultvalue);
            if (typesubkey == null) return description;

            //得到类型描述字符串  
            string typedescription = typesubkey.GetValue(null) as string;
            if (typedescription != null) description = typedescription;

            return description;
        }
    }

    /// <summary>
    /// 文件浏览器listView项数据
    /// </summary>
    public class ListIteam
    {
        public string name = "", type = "", iteam3 = "", iteam4 = "";   // 名称、类型、日期(总大小)、大小(可用空间)
        public int icon = -1;

        public ListIteam(){}


        //将当前对象的数据，转化为Json串
        public String ToJson()
        {
            return JsonConvert.SerializeObject(this);
        }

        //从Json串创建对象  
        public ListIteam Parse(string JsonStr)
        {
            return JsonConvert.DeserializeObject<ListIteam>(JsonStr);
        }

        // 数组的反序列化，返回对象数组
        public static List<ListIteam> Iteams(string JsonStr)
        {
            List<ListIteam> iteams = JsonConvert.DeserializeObject<List<ListIteam>>(JsonStr);
            return iteams;
        }

        //---------------

        // 从DirectoryInfo获取信息
        public ListIteam(DirectoryInfo dir)
        {
            name = dir.Name;
            type = "文件夹";
            iteam3 = dir.LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss");
            iteam4 = "";
        }

        // 从FileInfo获取信息
        public ListIteam(FileInfo file)
        {
            name = file.Name;
            type = FileInfoTool.GetDescription(file.Extension);
            iteam3 = file.LastWriteTime.ToString("yyyy/MM/dd HH:mm:ss");
            iteam4 = FileInfoTool.ToSizeStr(file.Length);
        }

        // 从DriveInfo获取信息
        public ListIteam(DriveInfo driver)
        {
            name = driver.Name;
            type = TypeName(driver.DriveType);
            try
            {
                iteam3 = FileInfoTool.ToSizeStr(driver.TotalSize);      // 总大小
                iteam4 = FileInfoTool.ToSizeStr(driver.TotalFreeSpace); // 可用空间
            }
            catch (Exception ex) 
            {
                iteam3 = "未知";
                iteam4 = "未知";
            }
        }

        private String TypeName(DriveType type)
        {
            if (type == DriveType.CDRom) return "光盘设备";
            else if (type == DriveType.Fixed) return "本地磁盘";
            else if (type == DriveType.Network) return "网络磁盘";
            else if (type == DriveType.NoRootDirectory) return "无根目录磁盘";
            else if (type == DriveType.Ram) return "RAM磁盘";
            else if (type == DriveType.Removable) return "可移动磁盘";
            else /*if (type == DriveType.Unknown)*/ return "未知类型磁盘";
        }

        /// <summary>
        /// 从当前数据信息创建listView项
        /// </summary>
        public ListViewItem CreatListViewIteam()
        {
            ListViewItem listIteam = new ListViewItem();
            listIteam.Text = name;

            listIteam.SubItems.Add(type);
            listIteam.SubItems.Add(iteam3);
            listIteam.SubItems.Add(iteam4);

            listIteam.ImageIndex = icon;

            return listIteam;
        }

        /// <summary>
        /// 从当前数据信息创建TreeNode
        /// </summary>
        public TreeNode CreateTreeNode()
        {
            TreeNode node = new TreeNode();
            node.Name = name;
            node.Text = name;

            return node;
        }
    }


    /// <summary>
    /// 记录文件名->图像数据信息
    /// </summary>
    public class IconData
    {
        public Dictionary<String, int> NameIndex = new Dictionary<string, int>();   // 记录名称与图像的映射信息
        public List<String> Datas = new List<string>();                             // 保存图像的数据信息

        public IconData()
        {
            //AddIcon("文件夹", SystemIcon.Get(3));
            //AddIcon("本地磁盘", SystemIcon.Get(8));
            //AddIcon("计算机", SystemIcon.Get(15));
            //AddIcon("桌面", SystemIcon.Get(34));
        }

        //将当前对象的数据，转化为Json串
        public String ToJson()
        {
            return JsonConvert.SerializeObject(this);
        }

        //从Json串创建对象  
        public IconData Parse(string JsonStr)
        {
            return JsonConvert.DeserializeObject<IconData>(JsonStr);
        }

        // 数组的反序列化，返回对象数组
        public static List<IconData> Iteams(string JsonStr)
        {
            List<IconData> iteams = JsonConvert.DeserializeObject<List<IconData>>(JsonStr);
            return iteams;
        }

        // --------

        /// <summary>
        /// 记录Name、icon信息到当前对象
        /// </summary>
        public void AddIcon(String Name, Icon icon)
        {
            if (!NameIndex.ContainsKey(Name))
            {
                String iconData = RecodeTool.Icon2String(icon);     // 图像转化为字符串形式
                if (!Datas.Contains(iconData)) Datas.Add(iconData); // 在图像数据集中,记录当前图像信息

                int imageIndex = Datas.IndexOf(iconData);           // 获取图像对应的数据索引信息
                NameIndex.Add(Name, imageIndex);                    // 记录名称索引信息
            }
        }

        /// <summary>
        /// 获取当前对象中保存的所有Icon信息为ImageList
        /// </summary>
        public ImageList getImageList()
        {
            ImageList imageList = new ImageList();
            imageList.ColorDepth = ColorDepth.Depth32Bit;
            imageList.ImageSize = new Size(24, 24);

            foreach (String imageData in Datas)                 // 获取所有icon图像数据
            {
                Icon icon = RecodeTool.String2Icon(imageData);  // 转化为对应的图像
                imageList.Images.Add(icon);                     // 添加图像至list
            }

            return imageList;
        }

    }

    /// <summary>
    /// 文件目录信息
    /// 
    /// 1、获取文件目录信息：DirInfo info = new DirInfo(FullName);
    /// 2、转化为字符串形式：String data = info.ToJson();
    /// 3、在listView中显示：info.ShowIn(listView1);
    /// </summary>
    public class DirInfo
    {
        public String Dir = "";                                 // 当前目录路径
        public List<ListIteam> subDirs = new List<ListIteam>(); // 目录下的文件夹信息
        public List<ListIteam> subFiles = new List<ListIteam>();// 目录下的文件信息

        public IconData iconData = new IconData();              // 文件目录相关的所有Icon图像信息
        public bool containsFile = true;                        // 是否包含文件信息

        //public ImageList imageList;

        public DirInfo() { }

        //将当前对象的数据，转化为Json串
        public String ToJson()
        {
            return JsonConvert.SerializeObject(this);
        }

        //从Json串创建对象  
        public DirInfo Parse(string JsonStr)
        {
            return JsonConvert.DeserializeObject<DirInfo>(JsonStr);
        }

        // 数组的反序列化，返回对象数组
        public static List<DirInfo> Iteams(string JsonStr)
        {
            List<DirInfo> iteams = JsonConvert.DeserializeObject<List<DirInfo>>(JsonStr);
            return iteams;
        }

        //---------------

        /// <summary>
        /// 从指定的目录创建DirInfo, 如 D:\test； 
        /// containsFile标识是否包含文件信息；
        /// </summary>
        public DirInfo(String DirPath, bool containsFile = true)
        {
            this.containsFile = containsFile;
            LoadDirInfo(DirPath);
        }

        /// <summary>
        /// 从指定的目录载入文件信息, 如 D:\test
        /// </summary>
        public void LoadDirInfo(String DirPath)
        {
            Dir = DirPath;
            subDirs.Clear();
            subFiles.Clear();
            iconData = new IconData();

            DirectoryInfo root = new DirectoryInfo(DirPath);

            try
            {
                // 添加文件夹信息
                Icon folderIcon = SystemIcon.Get(3);
                foreach (DirectoryInfo dirInfo in root.GetDirectories())
                {

                    iconData.AddIcon("文件夹", folderIcon); // 添加文件夹Icon信息

                    ListIteam iteam = new ListIteam(dirInfo);
                    iteam.icon = iconData.NameIndex["文件夹"];

                    subDirs.Add(iteam);

                }
            }
            catch (Exception ex) { }

            if (!containsFile) return;  // 若不需要文件信息，则不解析

            try
            {
                // 添加文件信息
                foreach (FileInfo fileInfo in root.GetFiles())
                {
                    Icon icon = FileIcon.getIcon2(fileInfo.FullName);   // 获取文件对应的icon图像
                    iconData.AddIcon(fileInfo.Name, icon);              // (按文件名)记录图像

                    ListIteam iteam = new ListIteam(fileInfo);
                    iteam.icon = iconData.NameIndex[fileInfo.Name];     // 获取文件名对应的图像索引

                    subFiles.Add(iteam);
                }
            }
            catch (Exception ex) { }

        }

        /// <summary>
        /// 在listView中显示目录中的文件信息
        /// </summary>
        public void ShowIn(ListView listView)
        {
            listView.View = View.Details;
            listView.AllowColumnReorder = true;
            listView.Columns.Clear();
            listView.Items.Clear();

            ImageList imageList = iconData.getImageList();  // 获取Icon信息

            listView.LargeImageList = imageList;
            listView.SmallImageList = imageList;

            listView.Columns.Add("Name", "名称", 270);
            listView.Columns.Add("Type", "类型", 120);
            listView.Columns.Add("Date", "修改日期", 140);
            listView.Columns.Add("Space", "文件大小", 80);
            listView.Columns["Space"].TextAlign = HorizontalAlignment.Right; //文件大小信息右对齐

            // 生成列表项
            List<ListViewItem> list = new List<ListViewItem>();

            String SP = (Dir.EndsWith("\\") ? "" : "\\");
            foreach (ListIteam iteam in subDirs)
            {
                ListViewItem listIteam = iteam.CreatListViewIteam();
                listIteam.Tag = "Dir:" + Dir + SP + iteam.name;
                list.Add(listIteam);
            }
            foreach (ListIteam iteam in subFiles)
            {
                ListViewItem listIteam = iteam.CreatListViewIteam();
                listIteam.Tag = "File:" + Dir + SP + iteam.name;
                list.Add(listIteam);
            }
            
            // 在listView中显示
            listView.Items.AddRange(list.ToArray());
        }

        /// <summary>
        /// 在treeNode子节点显示目录中的文件信息
        /// </summary>
        public void ShowIn(/*SystemDirTree dirTree, */ TreeNode treeNode)
        {
            if (treeNode.Tag == null) treeNode.Tag = "Dir:" + Dir;
            treeNode.Nodes.Clear();

            String SP = (Dir.EndsWith("\\") ? "" : "\\");
            foreach (ListIteam iteam in subDirs)
            {
                TreeNode node = iteam.CreateTreeNode();
                node.Tag = "Dir:" + Dir + SP + iteam.name;
                node.Text = iteam.name;

                //string StrIcon = iconData.Datas[iteam.icon];    // 获取icon
                //int index = dirTree.AddIcon(StrIcon);           // 添加icon

                int index = 4;
                node.ImageIndex = index;
                node.SelectedImageIndex = index;

                treeNode.Nodes.Add(node);
            }

            //foreach (ListIteam iteam in subFiles)
            //{
            //    TreeNode node = iteam.CreateTreeNode();
            //    node.Tag = "File:" + Dir + SP + iteam.name;
            //    node.Text = iteam.name;

            //    string StrIcon = iconData.Datas[iteam.icon];    // 获取icon
            //    int index = dirTree.AddIcon(StrIcon);           // 添加icon

            //    node.ImageIndex = index;
            //    node.SelectedImageIndex = index;

            //    treeNode.Nodes.Add(node);
            //}
        }

    }

    /// <summary>
    /// 系统磁盘信息
    /// 
    /// 1、获取本地磁盘信息：DriverInfo driver = new DriverInfo();
    /// 2、转化为字符串形式：string data = driver.ToJson();
    /// 3、在listView中显示：driver.ShowIn(listView1);
    /// </summary>
    public class DriverInfo
    {
        public List<ListIteam> drivers = new List<ListIteam>(); // 目录下的文件夹信息
        public IconData iconData = new IconData();              // 文件目录相关的所有Icon图像信息


        // 获取本地磁盘信息
        public DriverInfo() 
        {
            foreach (DriveInfo driver in DriveInfo.GetDrives())
            {
                ListIteam iteam = new ListIteam(driver);

                // 获取磁盘类型对应的icon信息
                if (!iconData.NameIndex.ContainsKey(iteam.type))
                {
                    Icon icon = getIcon(iteam.type);
                    iconData.AddIcon(iteam.type, icon);
                }
                iteam.icon = iconData.NameIndex[iteam.type];

                drivers.Add(iteam);
            }
        }

        private Icon getIcon(String type)
        {
            Icon icon;
            // 添加磁盘icon
            if (type == "光盘设备") icon = SystemIcon.Get(177);           // 添加本地磁盘Icon信息
            else if (type == "本地磁盘") icon = SystemIcon.Get(79);
            else if (type == "网络磁盘") icon = SystemIcon.Get(273);
            else if (type == "RAM磁盘") icon = SystemIcon.Get(194);
            else if (type == "可移动磁盘") icon = SystemIcon.Get(258);
            else if (type == "无根目录磁盘") icon = SystemIcon.Get(10);
            else /*if (type == "未知类型磁盘")*/ icon = SystemIcon.Get(53);

            return icon;
        }

        //将当前对象的数据，转化为Json串
        public String ToJson()
        {
            return JsonConvert.SerializeObject(this);
        }

        //从Json串创建对象  
        public DriverInfo Parse(string JsonStr)
        {
            return JsonConvert.DeserializeObject<DriverInfo>(JsonStr);
        }

        // 数组的反序列化，返回对象数组
        public static List<DriverInfo> Iteams(string JsonStr)
        {
            List<DriverInfo> iteams = JsonConvert.DeserializeObject<List<DriverInfo>>(JsonStr);
            return iteams;
        }

        //---------------

        /// <summary>
        /// 在listView中显示目录中的文件信息
        /// </summary>
        public void ShowIn(ListView listView)
        {
            listView.View = View.Details;
            listView.AllowColumnReorder = true;
            listView.Columns.Clear();
            listView.Items.Clear();

            ImageList imageList = iconData.getImageList();  // 获取Icon信息

            listView.LargeImageList = imageList;
            listView.SmallImageList = imageList;

            listView.Columns.Add("Name", "名称", 80);
            listView.Columns.Add("Type", "类型", 80);
            listView.Columns.Add("TotalSpace", "总大小", 100);
            listView.Columns.Add("FreeSpace", "可用空间", 100);

            listView.Columns["TotalSpace"].TextAlign = HorizontalAlignment.Right;   //文件大小信息右对齐
            listView.Columns["FreeSpace"].TextAlign = HorizontalAlignment.Right;    //文件大小信息右对齐

            // 生成列表项
            List<ListViewItem> list = new List<ListViewItem>();

            foreach (ListIteam iteam in drivers)
            {
                ListViewItem listIteam = iteam.CreatListViewIteam();
                listIteam.Tag = "Dir:" + iteam.name;
                list.Add(listIteam);
            }

            // 在listView中显示
            listView.Items.AddRange(list.ToArray());
        }

        /// <summary>
        /// 在TreeView指定节点中显示目录中的文件信息
        /// </summary>
        public void ShowIn(SystemDirTree dirTree, TreeNode treeNode)
        {
            if (treeNode.Tag == null) treeNode.Tag = "Driver:" + "我的电脑";
            treeNode.Nodes.Clear();

            foreach (ListIteam iteam in drivers)
            {
                TreeNode node = iteam.CreateTreeNode();
                node.Tag = "Dir:" + iteam.name;
                node.Text = iteam.name;

                string StrIcon = iconData.Datas[iteam.icon];    // 获取icon
                int index = dirTree.AddIcon(StrIcon);           // 添加icon

                node.ImageIndex = index;
                node.SelectedImageIndex = index;

                treeNode.Nodes.Add(node);
            }
        }
    }

    /// <summary>
    /// 系统目录树
    /// new SystemDirTree().ShowIn(treeView1);
    /// </summary>
    public class SystemDirTree
    {
        public IconData iconData = new IconData();              // 文件目录相关的所有Icon图像信息
        public DriverInfo driverInfo;                              // 系统目录信息

        //将当前对象的数据，转化为Json串
        public String ToJson()
        {
            return JsonConvert.SerializeObject(this);
        }

        //从Json串创建对象  
        public SystemDirTree Parse(string JsonStr)
        {
            return JsonConvert.DeserializeObject<SystemDirTree>(JsonStr);
        }

        // 数组的反序列化，返回对象数组
        public static List<SystemDirTree> Iteams(string JsonStr)
        {
            List<SystemDirTree> iteams = JsonConvert.DeserializeObject<List<SystemDirTree>>(JsonStr);
            return iteams;
        }

        //---------------


        /// <summary>
        /// 向当前对象中添加icon数据，返回icon索引值
        /// </summary>
        public int AddIcon(string StrIcon)
        {
            if (!iconData.Datas.Contains(StrIcon)) iconData.Datas.Add(StrIcon);
            return iconData.Datas.IndexOf(StrIcon);
        }

        public SystemDirTree()
        {
            iconData.AddIcon("桌面", SystemIcon.Get(34));
            iconData.AddIcon("文档", SystemIcon.Get(158));
            iconData.AddIcon("计算机", SystemIcon.Get(15));
            iconData.AddIcon("最近使用", SystemIcon.Get(213));
            iconData.AddIcon("文件夹", SystemIcon.Get(3));

            driverInfo = new DriverInfo();
        }

        [JsonIgnore]
        TreeNode desktop = new TreeNode();

        [JsonIgnore]
        TreeNode document = new TreeNode();

        [JsonIgnore]
        TreeNode computer = new TreeNode();

        [JsonIgnore]
        TreeNode recent = new TreeNode();

        private void InitView(TreeView tree)
        {
            desktop.Text = "桌面";
            document.Text = "文档";
            computer.Text = "计算机";
            recent.Text = "最近使用";

            desktop.SelectedImageIndex = desktop.ImageIndex = iconData.NameIndex[desktop.Text];
            document.SelectedImageIndex = document.ImageIndex = iconData.NameIndex[document.Text];
            computer.SelectedImageIndex = computer.ImageIndex = iconData.NameIndex[computer.Text];
            recent.SelectedImageIndex = recent.ImageIndex = iconData.NameIndex[recent.Text];

            tree.ShowLines = false;
            tree.Nodes.Clear();
            tree.Nodes.Add(desktop);
            tree.Nodes.Add(document);
            tree.Nodes.Add(computer);
            tree.Nodes.Add(recent);
            tree.ImageList = iconData.getImageList();
        }

        // 在TreeView中显示系统目录树
        public void ShowIn(TreeView tree)
        {
            InitView(tree);

            driverInfo.ShowIn(this, computer);             // 在computer节点显示本地磁盘信息

            string deskTop = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
            new DirInfo(deskTop).ShowIn(desktop);

            string docDir = Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments);
            new DirInfo(docDir).ShowIn(document);

            string recentDir = Environment.GetFolderPath(Environment.SpecialFolder.Recent);
            new DirInfo(recentDir).ShowIn(recent);

            tree.ImageList = iconData.getImageList();   // 更新图标信息

            // treeView事件
            tree.AfterExpand += new System.Windows.Forms.TreeViewEventHandler(this.TreeView_AfterExpand);
        }


        # region TreeView事件逻辑

        /// <summary>
        /// TreeView节点展开时，载入其下的子节点信息
        /// </summary>
        private void TreeView_AfterExpand(object sender, TreeViewEventArgs e)
        {
            reloadSubNode(e.Node);
        }

        /// <summary>
        /// 重载node节点下的子节点信息
        /// </summary>
        private void reloadSubNode(TreeNode node)
        {
            if (node == null) return;
            foreach (TreeNode n in node.Nodes)
            {
                loadNodeInfo(n);
            }
        }

        /// <summary>
        /// 载入node节点下的目录信息
        /// </summary>
        private void loadNodeInfo(TreeNode node)
        {
            if (node == null) return;
            String tag = node.Tag as String;

            if (tag.Contains("Driver:") || tag.Contains("Dir:"))
            {
                tag = tag.Substring(tag.IndexOf(":") + 1);
                DirInfo dirInfo = new DirInfo(tag, false);

                dirInfo.ShowIn(node);
            }
        }

        # endregion

    }

    //public class IconData
    //{
    //    public Icon icon;

    //    public IconData(Icon icon)
    //    {
    //        this.icon = icon;
    //    }

    //    public static void Test(Form form)
    //    {
    //        Icon icon = SystemIcon.Get(3);
    //        Bitmap bitmap = icon.ToBitmap();
    //        byte[] data = RecodeTool.Image2Bytes(bitmap);
    //        String Str = RecodeTool.Bytes2String(data);

    //        byte[] data2 = RecodeTool.String2Bytes(Str);
    //        Image pic = RecodeTool.Bytes2Image(data2);

    //        IntPtr ptr = ((Bitmap)pic).GetHicon();
    //        Icon icon2 = Icon.FromHandle(ptr);

    //        form.Icon = icon2;
    //    }

    //    //将当前对象的数据，转化为Json串
    //    public String ToJson()
    //    {
    //        return JsonConvert.SerializeObject(this);
    //    }

    //    //从Json串创建对象  
    //    public static IconData Parse(string JsonStr)
    //    {
    //        return JsonConvert.DeserializeObject<IconData>(JsonStr);
    //    }
    //}

}

